﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
using Quizz.DataRepository.Models;

namespace Quizz.Service.Services
{
    public class MenuService : QuizzDomainService<QuizzDataContext>
    {
        public Menu GetById(long id)
        {
            return CompiledMenuService.GetById(this.DataContext, id);
        }

        public IEnumerable<Menu> GetAllParent()
        {
            return CompiledMenuService.GetAllParent(this.DataContext);
        }

        public IEnumerable<Menu> GetChilds(long? parentId)
        {
            return CompiledMenuService.GetChilds(this.DataContext, parentId);
        }

        public IEnumerable<Menu> GetParentMenuForRole(long role)
        {
            return CompiledMenuService.GetParentMenuForRole(DataContext, role);
        }

        public IEnumerable<Menu> GetChildMenuForRole(long? parent, long role)
        {
            return CompiledMenuService.GetChildMenuForRole(DataContext, parent, role);
        }

        public IEnumerable<Menu> GetAllForRole(long role)
        {
            return CompiledMenuService.GetAllForRole(DataContext, role);
        }

        public IEnumerable<Menu> GetMenuForAnonymous()
        {
            return CompiledMenuService.GetMenuForAnonymous(DataContext);
        }

        public void Insert(Menu menu)
        {
            this.DataContext.Menus.InsertOnSubmit(menu);
            this.DataContext.SubmitChanges();
        }

        public void Update(Menu menu){
            string sql = @"UPDATE [Menu] SET"
                             + @"[Name] = {0}, [Url] = {1}, [Content] = {2},"
                             + @"[Order] = {3}, [Type] = {4},"
                             + @"[ParentMenuId] = {5}, [ForRole] = {6}"
                             + @" WHERE [Id] = {7}";
            ExecuteCommand(sql, menu.Name, menu.Url, menu.Content, menu.Order, menu.Type, menu.ParentMenuId,
                           menu.ForRole, menu.Id);
        }

        public void Delete(long id)
        {
            string sql = @"DELETE [Menu] WHERE [Id] = {0}";
            ExecuteCommand(sql, id);
        }

        public Menu GetByUrl(string baseUrl)
        {
            return CompiledMenuService.GetMenuByUrl(DataContext, baseUrl);
        }
    }

    internal static class CompiledMenuService
    {
        public static Func<QuizzDataContext, long, Menu> GetById =
            CompiledQuery.Compile<QuizzDataContext, long, Menu>((ctx, id) => ctx.Menus.FirstOrDefault(m => m.Id == id));

        public static Func<QuizzDataContext, IEnumerable<Menu>> GetAllParent =
            CompiledQuery.Compile<QuizzDataContext, IEnumerable<Menu>>(
                ctx => ctx.Menus.Where(m => m.ParentMenuId == null).OrderBy(m => m.Order));

        public static Func<QuizzDataContext, long?, IEnumerable<Menu>> GetChilds =
            CompiledQuery.Compile<QuizzDataContext, long?, IEnumerable<Menu>>(
                (ctx, parent) =>
                from m in ctx.Menus
                where parent == null ? m.ParentMenuId == null : m.ParentMenuId.Equals(parent)
                select m);

        public static Func<QuizzDataContext, long, IEnumerable<Menu>> GetParentMenuForRole =
            CompiledQuery.Compile<QuizzDataContext, long, IEnumerable<Menu>>(
                (ctx, role) => ctx.Menus.Where(m => m.ForRole >= role || m.ForRole == -1));

        public static Func<QuizzDataContext, long?, long, IEnumerable<Menu>> GetChildMenuForRole =
            CompiledQuery.Compile<QuizzDataContext, long?, long, IEnumerable<Menu>>(
                (ctx, parent, role) => from m in ctx.Menus
                                       where
                                           (parent == null ? m.ParentMenuId == null : m.ParentMenuId == parent) &&
                                           (m.ForRole >= role || m.ForRole == -1)
                                       select m);

        public static Func<QuizzDataContext, IEnumerable<Menu>> GetMenuForAnonymous =
            CompiledQuery.Compile<QuizzDataContext, IEnumerable<Menu>>(ctx => ctx.Menus.Where(m => m.ForRole == -1));

        public static Func<QuizzDataContext, long, IEnumerable<Menu>> GetAllForRole =
            CompiledQuery.Compile<QuizzDataContext, long, IEnumerable<Menu>>(
                (ctx, role) =>
                from m in ctx.Menus where m.ForRole >= role || m.ForRole == -1 orderby m.ParentMenuId , m.Order select m);

        public static Func<QuizzDataContext, string, Menu> GetMenuByUrl =
            CompiledQuery.Compile<QuizzDataContext, string, Menu>(
                (ctx, url) => ctx.Menus.Where(m => m.Url.StartsWith(url)).FirstOrDefault());
    }
}
